"""
服务器启动脚本 - 行业最佳实践

遵循以下原则：
1. 启动前清理旧进程
2. 端口冲突检测
3. 优雅启动和关闭
4. 健康检查
5. 日志记录
"""

import os
import sys
import time
import subprocess
import signal
import logging
from pathlib import Path

# 添加父目录到路径
sys.path.insert(0, str(Path(__file__).parent.parent))

from scripts.cleanup_processes import ProcessManager

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)


class ServerStarter:
    """服务器启动器"""

    def __init__(self, port: int = 8000, host: str = "0.0.0.0"):
        self.port = port
        self.host = host
        self.process = None
        self.backend_dir = Path(__file__).parent.parent

    def cleanup_old_processes(self):
        """清理旧进程"""
        logger.info("=== Cleaning up old processes ===")
        manager = ProcessManager(port=self.port)
        stats = manager.cleanup_all()

        if not stats['port_released']:
            raise RuntimeError(f"Failed to release port {self.port}")

        logger.info("Old processes cleaned up successfully")

    def check_dependencies(self):
        """检查依赖"""
        logger.info("=== Checking dependencies ===")

        # 检查虚拟环境
        venv_python = self.backend_dir / "venv" / "Scripts" / "python.exe"
        if sys.platform != 'win32':
            venv_python = self.backend_dir / "venv" / "bin" / "python"

        if not venv_python.exists():
            raise RuntimeError(f"Virtual environment not found at {venv_python}")

        logger.info(f"Virtual environment found: {venv_python}")

        # 检查uvicorn
        try:
            result = subprocess.run(
                [str(venv_python), "-m", "uvicorn", "--version"],
                capture_output=True,
                text=True,
                check=True
            )
            logger.info(f"Uvicorn version: {result.stdout.strip()}")
        except subprocess.CalledProcessError:
            raise RuntimeError("Uvicorn not installed in virtual environment")

    def start_server(self, reload: bool = True):
        """启动服务器"""
        logger.info(f"=== Starting server on {self.host}:{self.port} ===")

        venv_python = self.backend_dir / "venv" / "Scripts" / "python.exe"
        if sys.platform != 'win32':
            venv_python = self.backend_dir / "venv" / "bin" / "python"

        cmd = [
            str(venv_python),
            "-m", "uvicorn",
            "app.main:app",
            "--host", self.host,
            "--port", str(self.port),
        ]

        if reload:
            cmd.append("--reload")

        # 设置环境变量
        env = os.environ.copy()
        env['PYTHONUNBUFFERED'] = '1'  # 禁用输出缓冲

        logger.info(f"Command: {' '.join(cmd)}")

        try:
            self.process = subprocess.Popen(
                cmd,
                cwd=str(self.backend_dir),
                env=env,
                stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT,
                text=True,
                bufsize=1
            )

            logger.info(f"Server process started with PID {self.process.pid}")
            return self.process

        except Exception as e:
            logger.error(f"Failed to start server: {e}")
            raise

    def wait_for_health(self, timeout: int = 30):
        """等待服务器健康检查"""
        import urllib.request
        import urllib.error

        logger.info("=== Waiting for server to be healthy ===")

        health_url = f"http://localhost:{self.port}/docs"
        start_time = time.time()

        while time.time() - start_time < timeout:
            try:
                with urllib.request.urlopen(health_url, timeout=2) as response:
                    if response.status == 200:
                        logger.info(f"Server is healthy! ({health_url})")
                        return True
            except urllib.error.URLError:
                pass

            # 检查进程是否还在运行
            if self.process and self.process.poll() is not None:
                logger.error("Server process terminated unexpectedly")
                return False

            time.sleep(1)

        logger.error(f"Server did not become healthy within {timeout} seconds")
        return False

    def stream_output(self):
        """流式输出服务器日志"""
        if not self.process:
            return

        logger.info("=== Server output (Ctrl+C to stop) ===")

        try:
            for line in self.process.stdout:
                print(line, end='')
        except KeyboardInterrupt:
            logger.info("\nReceived interrupt signal")
            self.shutdown()

    def shutdown(self):
        """优雅关闭服务器"""
        if not self.process:
            return

        logger.info("=== Shutting down server ===")

        try:
            # 发送 SIGTERM
            self.process.terminate()

            # 等待最多5秒
            try:
                self.process.wait(timeout=5)
                logger.info("Server terminated gracefully")
            except subprocess.TimeoutExpired:
                # 强制终止
                logger.warning("Server did not terminate gracefully, forcing...")
                self.process.kill()
                self.process.wait()
                logger.info("Server forcefully killed")

        except Exception as e:
            logger.error(f"Error during shutdown: {e}")


def main():
    """主函数"""
    import argparse

    parser = argparse.ArgumentParser(description='Start the backend server')
    parser.add_argument('--port', type=int, default=8000, help='Port to run on (default: 8000)')
    parser.add_argument('--host', default='0.0.0.0', help='Host to bind to (default: 0.0.0.0)')
    parser.add_argument('--no-reload', action='store_true', help='Disable auto-reload')
    parser.add_argument('--no-cleanup', action='store_true', help='Skip cleanup of old processes')

    args = parser.parse_args()

    starter = ServerStarter(port=args.port, host=args.host)

    try:
        # Step 1: 清理旧进程
        if not args.no_cleanup:
            starter.cleanup_old_processes()

        # Step 2: 检查依赖
        starter.check_dependencies()

        # Step 3: 启动服务器
        starter.start_server(reload=not args.no_reload)

        # Step 4: 健康检查
        if starter.wait_for_health():
            # Step 5: 流式输出日志
            starter.stream_output()
        else:
            logger.error("Server failed to start properly")
            sys.exit(1)

    except KeyboardInterrupt:
        logger.info("Received interrupt signal")
        starter.shutdown()
    except Exception as e:
        logger.error(f"Startup failed: {e}")
        starter.shutdown()
        sys.exit(1)
    finally:
        starter.shutdown()


if __name__ == '__main__':
    main()
